package com.ymx.darling.logicdelete;

import com.ymx.darling.bean.entity.BeanInfo;
import com.ymx.darling.bean.entity.FieldInfo;
import com.ymx.darling.logicdelete.impl.BooleanLogicDeleteProcessor;
import com.ymx.darling.logicdelete.impl.IntegerLogicDeleteProcessor;
import com.ymx.darling.logicdelete.impl.TimestampDeleteProcessor;
import com.ymx.darling.wrapper.UpdateWrapper;
import com.ymx.darling.wrapper.Wrapper;
import com.ymx.darling.bean.entity.TableAlias;
import com.ymx.darling.wrapper.fragment.WhereSegment;

import java.sql.Timestamp;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * 逻辑删除处理器
 * @author 爱Java的小于
 */
public class LogicDeleteManager {
    private static final ThreadLocal<Boolean> skipFlags = new ThreadLocal<>();
    private static Consumer<UpdateWrapper> afterSetLogicDeleteProcessor; // 逻辑删除后置处理器

    private static final Map<Class<?>, LogicDeleteProcessor> logicDeleteProcessorMap = new HashMap<>();

    static {
        logicDeleteProcessorMap.put(Integer.TYPE, new IntegerLogicDeleteProcessor());
        logicDeleteProcessorMap.put(Integer.class, new IntegerLogicDeleteProcessor());
        logicDeleteProcessorMap.put(Long.TYPE, new IntegerLogicDeleteProcessor());
        logicDeleteProcessorMap.put(Long.class, new IntegerLogicDeleteProcessor());
        logicDeleteProcessorMap.put(Short.TYPE, new IntegerLogicDeleteProcessor());
        logicDeleteProcessorMap.put(Short.class, new IntegerLogicDeleteProcessor());
        logicDeleteProcessorMap.put(Byte.TYPE, new IntegerLogicDeleteProcessor());
        logicDeleteProcessorMap.put(Byte.class, new IntegerLogicDeleteProcessor());
        logicDeleteProcessorMap.put(Boolean.TYPE, new BooleanLogicDeleteProcessor());
        logicDeleteProcessorMap.put(Boolean.class, new BooleanLogicDeleteProcessor());
        logicDeleteProcessorMap.put(Timestamp.class, new TimestampDeleteProcessor());
    }

    public static <T> T execWithoutLogicDelete(Supplier<T> supplier) {
        T result;
        try {
            skip();
            result = supplier.get();
        } finally {
            restore();
        }

        return result;
    }


    public static void execWithoutLogicDelete(Runnable runnable) {
        try {
            skip();
            runnable.run();
        } finally {
            restore();
        }
    }


    /**
     * 临时关闭逻辑删除
     */
    private static void skip() {
        skipFlags.set(Boolean.TRUE);
    }


    /**
     * 恢复逻辑删除设置
     */
    private static void restore() {
        skipFlags.remove();
    }


    /**
     * 判断是否临时跳过逻辑删除
     * @return boolean
     */
    private static boolean isSkip() {
        return skipFlags.get() == Boolean.TRUE;
    }


    /**
     * 为wrapper添加逻辑删除条件
     * @param tableName 表名(包含别名)
     * @param wrapper wrapper
     */
    public static void addConditionByWrapper(FieldInfo logicDeleteColumn, String tableName, Wrapper<?> wrapper) {
        LogicDeleteProcessor logicDeleteProcessor = logicDeleteColumn.getLogicDeleteProcessor();
        TableAlias tableAlias = TableAlias.splitTableAndAlias(tableName);
        String conditionTableName = tableAlias.hasAlias() ? tableAlias.getAliasName() : tableName;
        logicDeleteProcessor.setWrapperCondition(conditionTableName, logicDeleteColumn, wrapper);
    }


    /**
     * 为where添加逻辑删除条件
     * @param tableName 表名(包含别名)
     * @param whereSegment whereSegment
     */
    public static void addConditionByWhere(FieldInfo logicDeleteColumn, String tableName, WhereSegment whereSegment) {
        LogicDeleteProcessor logicDeleteProcessor = logicDeleteColumn.getLogicDeleteProcessor();
        TableAlias tableAlias = TableAlias.splitTableAndAlias(tableName);
        String conditionTableName = tableAlias.hasAlias() ? tableAlias.getAliasName() : tableName;
        logicDeleteProcessor.setWhereCondition(conditionTableName, logicDeleteColumn, whereSegment);
    }


    /**
     * 根据传入不同类型返回不同的逻辑删除处理器
     * @param type Class
     * @return LogicDeleteProcessor 没有对应的处理器时返回null
     */
    public static LogicDeleteProcessor getLogicDeleteProcessor(Class<?> type) {
        return logicDeleteProcessorMap.get(type);
    }


    /**
     * 注册自定义的逻辑处理器
     * @param fieldType 逻辑删除字段的类型
     * @param logicDeleteProcessor 自定义逻辑处理器
     */
    public static void registerLogicDeleteProcessor(Class<?> fieldType, LogicDeleteProcessor logicDeleteProcessor) {
        logicDeleteProcessorMap.put(fieldType, logicDeleteProcessor);
    }

    /**
     * 获取逻辑删除字段的处理器
     * @return Consumer
     */
    protected static Consumer<UpdateWrapper> getAfterSetLogicDeleteProcessor() {
        return afterSetLogicDeleteProcessor;
    }


    /**
     * 注册一个逻辑删除后置处理器
     * @param afterSetLogicDeleteProcessor 逻辑删除后置处理器
     */
    public static void registerAfterSetLogicDeleteProcessor(Consumer<UpdateWrapper> afterSetLogicDeleteProcessor) {
        LogicDeleteManager.afterSetLogicDeleteProcessor = afterSetLogicDeleteProcessor;
    }


    /**
     * 判断指定BeanInfo是否开启了逻辑删除
     * @param beanInfo beanInfo
     * @return boolean
     */
    public static boolean isLogicDeleteEnabled(BeanInfo beanInfo) {
        return !isSkip() &&
                Objects.nonNull(beanInfo) &&
                Objects.nonNull(beanInfo.getLogicDeleteColumn());
    }
}
